package cn.jcby.app.lebu.service.impl;

import cn.jcby.app.config.QiNiuConfig;
import cn.jcby.app.excpt.enums.ExceptionMsgEnum;
import cn.jcby.app.lebu.controller.req.*;
import cn.jcby.app.lebu.controller.res.PlaningInfoRes;
import cn.jcby.app.lebu.controller.res.UserMotionPlanInfoRes;
import cn.jcby.app.lebu.controller.res.UserMotionPlanListRes;
import cn.jcby.app.lebu.dao.UserDao;
import cn.jcby.app.lebu.dao.UserMotionPlanDao;
import cn.jcby.app.lebu.entity.DictEntity;
import cn.jcby.app.lebu.entity.DistributionTemplateEntity;
import cn.jcby.app.lebu.entity.UserEntity;
import cn.jcby.app.lebu.entity.UserMotionPlanEntity;
import cn.jcby.app.lebu.enums.CompleteTypeEnum;
import cn.jcby.app.lebu.enums.MessageTypeEnum;
import cn.jcby.app.lebu.enums.MotionPlanStatusEnum;
import cn.jcby.app.lebu.service.DictService;
import cn.jcby.app.lebu.service.DistributionTemplateService;
import cn.jcby.app.lebu.service.UserMessageService;
import cn.jcby.app.lebu.service.UserMotionPlanService;
import cn.jcby.app.lebu.utils.PageUtils;
import cn.jcby.app.lebu.utils.UserInfoUtil;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Service("userMotionPlanService")
public class UserMotionPlanServiceImpl extends ServiceImpl<UserMotionPlanDao, UserMotionPlanEntity> implements UserMotionPlanService {

    @Autowired
    private DictService dictService;
    @Autowired
    private UserDao usersDao;
    @Autowired
    private DistributionTemplateService distributionTemplateService;
    @Autowired
    private UserMessageService messageService;


    @Autowired
    private QiNiuConfig qiNiuConfig;

    @Value("${constants.nearBy.distance}")
    private Double nearByDistance ;

    @Override
    public PageUtils myMotionPage(UserMotionPlanListReq req) {
        req.setUserId(UserInfoUtil.getUserId());
        req.setNowTime(new Date());
        Integer count = this.baseMapper.myMotionCount(req);
        PageUtils pageUtils = new PageUtils(null,count,req.getLimit(),req.getPage());
        if(count > 0){
            List<UserMotionPlanListRes> list = this.baseMapper.myMotionList(req);
            extracted(list);
            pageUtils.setList(list);
        }
        return pageUtils ;
    }
    @Override
    public PageUtils publisherNewPage(PublisherListReq req) {
        req.setNowTime(new Date());
        Integer count = this.baseMapper.publisherNewCount(req);
        PageUtils pageUtils = new PageUtils(null,count,req.getLimit(),req.getPage());

        if(count > 0){
            List<UserMotionPlanListRes> list = this.baseMapper.publisherNewList(req);
            extracted(list);
            pageUtils.setList(list);
        }
        return pageUtils ;
    }

    @Override
    public void deleteByIdList(List<String> idList) {
        this.baseMapper.deleteByIdList(idList) ;
    }

    @Override
    public PlaningInfoRes planingInfo(String id) {
        UserMotionPlanEntity entity = getById(id);
        Assert.isFalse(entity==null, ExceptionMsgEnum.RECORD_NOT_EXIST.getCode()+"");
        PlaningInfoRes res = new PlaningInfoRes() ;
        BeanUtils.copyProperties(entity,res);
        List<DictEntity> dictList = dictService.list(Wrappers.<DictEntity>lambdaQuery());
        if(StringUtils.isNotEmpty(entity.getMotionType())){
            String name = dictList.stream().filter(p -> p.getCode().equals(entity.getMotionType())).findFirst().orElse(new DictEntity()).getName();
            res.setMotionTypeDesc(name);
        }
        if (StringUtils.isNotBlank(entity.getMotionMileageCode())){
            String name = dictList.stream().filter(p -> p.getCode().equals(entity.getMotionMileageCode())).findFirst().orElse(new DictEntity()).getName();
            res.setMotionMileageDesc(name);
        }
        return res;
    }

    @Override
    public void finishPlan(FinishPlanReq req) {
        //完成计划
        UserMotionPlanEntity entity = getById(req.getId());
        Assert.isFalse(entity==null, ExceptionMsgEnum.RECORD_NOT_EXIST.getCode()+"");
        //完成计划
        req.setCompleteTime(new Date());
        req.setCompleteType(CompleteTypeEnum.COMPLETE_NORMAL.getCode());
        req.setStatus(MotionPlanStatusEnum.COMPLETE.getCode());
        this.baseMapper.publisherCompletedPlan(req);
        //完成分销
        completePlan(entity) ;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completePlan(UserMotionPlanEntity e) {

        List<DistributionTemplateEntity> templateList = distributionTemplateService.list();
        //参与者扣除能量值
        usersDao.completeAndUnlockEnergy(e.getParticipantUserId(),e.getEmerge(),e.getMotionMileage()) ;
        //发起者分的能量值
        BigDecimal amount = e.getEmerge() ;
        DistributionTemplateEntity distributionTemplateEntity = templateList.stream().filter(p -> p.getGrade() == 0).findFirst().orElse(null);
        if (distributionTemplateEntity!=null){
            amount = amount.multiply(distributionTemplateEntity.getRate());
        }else{
            //默认 70%
            amount = amount.multiply(templateList.get(0).getRate());
        }
        usersDao.gainRevenue(e.getUserId(),amount) ;
        //TODO 自动完成，分销
        //查询发起者父级级别，如果父级为1级有比例分成，父父级为2级有比例分成，父父父级为3级有比例分成
        UserEntity entity = usersDao.selectById(e.getUserId());
        if (StringUtils.isNotBlank(entity.getParentInviteCode())){
            fenxiao(entity.getParentInviteCode(),templateList,e.getEmerge(),1);
        }
    }

    //分销方法
    private void fenxiao(String inviteCode,List<DistributionTemplateEntity> templateList,BigDecimal amount,int limitGrade){
        UserEntity one = usersDao.selectOne(Wrappers.<UserEntity>lambdaQuery().eq(UserEntity::getInviteCode, inviteCode));
        if (one!=null){
            if(one.getGrade()>=limitGrade){
                templateList.stream().filter(e -> e.getGrade().equals(limitGrade)).findFirst().ifPresent(p -> {
                    BigDecimal tempAmount = amount.multiply(p.getRate());
                    usersDao.gainRevenue(one.getId(),tempAmount);
                });
                if(StringUtils.isNotBlank(one.getParentInviteCode())) {
                    fenxiao(one.getParentInviteCode(), templateList, amount,limitGrade+1);
                }
            }
        }
    }

    private void extracted(List<UserMotionPlanListRes> list) {
        if(CollectionUtils.isNotEmpty(list)){
            List<DictEntity> dictList = dictService.list();
            list.stream().forEach(e->{
                if(StringUtils.isNotEmpty(e.getMotionType())){
                    String name = dictList.stream().filter(p -> p.getCode().equals(e.getMotionType())).findFirst().orElse(new DictEntity()).getName();
                    e.setMotionTypeDesc(name);
                }
                if(StringUtils.isNotEmpty(e.getMotionMileageCode())){
                    String name = dictList.stream().filter(p -> p.getCode().equals(e.getMotionMileageCode())).findFirst().orElse(new DictEntity()).getName();
                    e.setMotionMileageDesc(name);
                }
            });
        }
    }


    @Override
    public void add(AddUserMotionPlanReq req){
        req.check();
        UserMotionPlanEntity userMotionPlan = new UserMotionPlanEntity() ;
        //组装数据
        BeanUtils.copyProperties(req,userMotionPlan) ;
        userMotionPlan.setUserId(UserInfoUtil.getUserId());
        userMotionPlan.setDelType(0);
        userMotionPlan.setDel(0);
        userMotionPlan.setCreateTime(new Date());
        userMotionPlan.setUpdateTime(new Date());
        //里程
        List<DictEntity> dictList = dictService.list();
        if(StringUtils.isNotEmpty(req.getMotionMileageCode())) {
            DictEntity motionDict = dictList.stream().filter(p -> p.getCode().equals(req.getMotionMileageCode())).findFirst().orElse(null);
            Assert.isFalse(motionDict == null, "运动距离不存在");
            userMotionPlan.setMotionMileage(BigDecimal.valueOf(Double.valueOf(motionDict.getName().replace("KM",""))).multiply(BigDecimal.valueOf(1000)));
        }
        //能量
        DictEntity emergeDict = dictList.stream().filter(p -> p.getCode().equals(req.getEmergeCode())).findFirst().orElse(null);
        Assert.isFalse(emergeDict == null, "能量包不存在");
        userMotionPlan.setEmerge(BigDecimal.valueOf(Double.valueOf(emergeDict.getName())));
        userMotionPlan.setId(IdWorker.get32UUID());
        userMotionPlan.setStatus(MotionPlanStatusEnum.NEW_PUBLISH.getCode());
        this.baseMapper.addPlan(userMotionPlan); ;
    }

    @Override
    public void updateBy(UserMotionPlanEntity userMotionPlanReq){
        UserMotionPlanEntity userMotionPlan = new UserMotionPlanEntity() ;
        updateById(userMotionPlan) ;
    }


    @Override
    public UserMotionPlanInfoRes getInfoById(String id) {
        UserMotionPlanInfoRes res = new UserMotionPlanInfoRes();
        UserMotionPlanEntity userMotionPlanEntity = this.baseMapper.selectById(id);
        if(userMotionPlanEntity!= null) {
            UserEntity user = usersDao.selectById(userMotionPlanEntity.getUserId());
            List<DictEntity> list = dictService.list(Wrappers.<DictEntity>lambdaQuery().eq(DictEntity::getDel, 0)) ;
            BeanUtils.copyProperties(userMotionPlanEntity,res);
            if (StringUtils.isNotEmpty(res.getMotionType())){
                //运动类型
                res.setMotionTypeDesc(list.stream().filter(dictEntity -> dictEntity.getCode().equals(res.getMotionType())).findFirst().orElse(new DictEntity()).getName());
            }
            if (StringUtils.isNotEmpty(res.getMotionMileageCode())){
                //运动距离
                res.setMotionMileageDesc(list.stream().filter(dictEntity -> dictEntity.getCode().equals(res.getMotionMileageCode())).findFirst().orElse(new DictEntity()).getName());
            }
            if (StringUtils.isNotEmpty(res.getEmergeCode())){
                //能量包
                res.setEmergeDesc(list.stream().filter(dictEntity -> dictEntity.getCode().equals(res.getEmergeCode())).findFirst().orElse(new DictEntity()).getName());
            }
            res.setNickName(user.getNickName());
            if (StringUtils.isNotBlank(user.getFaceUrl())) {
                res.setFaceUrl(qiNiuConfig.getDomain() +"/" +user.getFaceUrl());
            }
        }
        return res;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void joinPlan(String id) {
        UserMotionPlanEntity entity = getById(id);
        //自己不能参与自己
        Assert.isFalse(UserInfoUtil.getUserId().equals(entity.getUserId()), ExceptionMsgEnum.USER_CAN_NOT_JOIN_SELF.getCode()+"");
        Assert.isFalse(entity == null, ExceptionMsgEnum.USER_HAS_JOIN_NOT_EXIST.getCode()+"");
        Assert.isFalse(entity.getStatus() != 0, ExceptionMsgEnum.USER_HAS_JOIN_OVER.getCode()+"");
        Assert.isFalse(UserInfoUtil.getUserId().equals(entity.getParticipantUserId()), ExceptionMsgEnum.USER_HAS_JOIN.getCode()+"");
        //验证参与人金额是否满足
        UserEntity user = usersDao.selectById(UserInfoUtil.getUserId());
        Assert.isFalse(user==null, ExceptionMsgEnum.USER_NOT_EXIST.getCode()+"");
        //判断性别
        if(entity.getLimitGender()!= null && entity.getLimitGender()!= 2) {
            Assert.isFalse(!entity.getLimitGender().equals(user.getGender()) , ExceptionMsgEnum.USER_SEX_NOT_MATCH.getCode()+"");
        }
        Assert.isFalse(user.getEnergy().subtract(user.getLockedEnergy()).compareTo(entity.getEmerge()) == -1, ExceptionMsgEnum.ENERGY_NOT_ENOUGH.getCode()+"");

        UserMotionPlanEntity updateEntity = new UserMotionPlanEntity() ;
        updateEntity.setId(id);
        updateEntity.setStatus(MotionPlanStatusEnum.IN_PROGRESS.getCode());
        updateEntity.setParticipantUserId(UserInfoUtil.getUserId());
        this.baseMapper.joinPlan(updateEntity) ;
        //锁定用户能量值
        usersDao.lockEnergy(UserInfoUtil.getUserId(),entity.getEmerge()) ;
        //添加消息
        messageService.addRecord(UserInfoUtil.getUserId(),entity.getUserId(), MessageTypeEnum.JOIN_REMIND);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelJoinPlan(String id) {
        //取消计划，当前时间必须在计划开始的1小时之前可取消，取消后，状态返回为新发布，金额退回
        UserMotionPlanEntity one = getOne(Wrappers.<UserMotionPlanEntity>lambdaQuery()
                        .eq(UserMotionPlanEntity::getId, id)
                        .eq(UserMotionPlanEntity::getParticipantUserId, UserInfoUtil.getUserId())
                        .eq(UserMotionPlanEntity::getStatus, MotionPlanStatusEnum.IN_PROGRESS.getCode())
                //.le(UserMotionPlanEntity::getStartTime, DateUtils.addHours(new Date(), -1))
        );
        Assert.isFalse(one == null, ExceptionMsgEnum.USER_NOT_JOIN.getCode()+"");

        //当前时间必须在计划开始的1小时之前可取消
        if(one.getBeginTime().getTime() - System.currentTimeMillis() > 60*60*1000){
            UserMotionPlanEntity updateEntity = new UserMotionPlanEntity() ;
            updateEntity.setId(id);
            updateEntity.setStatus(MotionPlanStatusEnum.NEW_PUBLISH.getCode());
            updateEntity.setParticipantUserId(null);
            this.baseMapper.joinPlan(updateEntity) ;
            //解锁用户能量值
            usersDao.unlockEnergy(UserInfoUtil.getUserId(),one.getEmerge()) ;

            messageService.addRecord(UserInfoUtil.getUserId(),one.getUserId(), MessageTypeEnum.CANCEL_REMIND_PRO);
        }else{
            Date date = new Date(one.getBeginTime().getTime() - 60 * 60 * 1000);
            int hours = date.getHours();
            int seconds = date.getSeconds();
            throw new RuntimeException(hours+"小时"+seconds+"秒之后不能取消");
        }

    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void proCancelJoinPlan(String id) {
        //取消计划，当前时间必须在计划开始的1小时之前可取消，取消后，状态返回为新发布，金额退回
        UserMotionPlanEntity one = getOne(Wrappers.<UserMotionPlanEntity>lambdaQuery()
                        .eq(UserMotionPlanEntity::getId, id)
                        .eq(UserMotionPlanEntity::getUserId, UserInfoUtil.getUserId())
                        .eq(UserMotionPlanEntity::getStatus, MotionPlanStatusEnum.IN_PROGRESS.getCode())
                //.le(UserMotionPlanEntity::getStartTime, DateUtils.addHours(new Date(), -1))
        );
        Assert.isFalse(one == null, ExceptionMsgEnum.RECORD_NOT_EXIST.getCode()+"");

        //当前时间必须在计划开始的1小时之前可取消
        if(one.getBeginTime().getTime() - System.currentTimeMillis() > 60*60*1000){
            UserMotionPlanEntity updateEntity = new UserMotionPlanEntity() ;
            updateEntity.setId(id);
            updateEntity.setStatus(MotionPlanStatusEnum.NEW_PUBLISH.getCode());
            updateEntity.setParticipantUserId(null);
            this.baseMapper.joinPlan(updateEntity) ;
            //解锁用户能量值
            usersDao.unlockEnergy(one.getParticipantUserId(),one.getEmerge()) ;

            messageService.addRecord(UserInfoUtil.getUserId(),one.getParticipantUserId(), MessageTypeEnum.CANCEL_REMIND_PARTICIPANT);
        }else{
            Date date = new Date(one.getBeginTime().getTime() - 60 * 60 * 1000);
            int hours = date.getHours();
            int seconds = date.getSeconds();
            throw new RuntimeException(hours+"小时"+seconds+"秒之后不能取消");
        }

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(String id) {
        //发起人删除计划、发起人/参与人删除已完成的计划
        UserMotionPlanEntity plan = getById(id);
        Assert.isFalse(plan == null, ExceptionMsgEnum.USER_HAS_JOIN_NOT_EXIST.getCode()+"");
        Assert.isFalse(MotionPlanStatusEnum.IN_PROGRESS.getCode().equals(plan.getStatus()) , ExceptionMsgEnum.USER_CAN_NOT_DELETE_IN_PROGRESS.getCode()+"");
        if(plan.getStatus().equals(MotionPlanStatusEnum.COMPLETE.getCode())){
            if (UserInfoUtil.getUserId().equals(plan.getUserId())){
                //发起人隐藏,判断参与人是否已经隐藏
                if(plan.getDelType() == 2){
                    this.baseMapper.hide(id, 3);
                }else {
                    this.baseMapper.hide(id, 1);
                }
            }else if(UserInfoUtil.getUserId().equals(plan.getParticipantUserId())){
                //参与人隐藏,判断发起人是否隐藏
                if(plan.getDelType() == 1){
                    this.baseMapper.hide(id, 3);
                }else {
                    this.baseMapper.hide(id, 2);
                }
            }
        }else{
            //发起中，计划人可以删除
            Assert.isFalse(!plan.getUserId().equals(UserInfoUtil.getUserId()), ExceptionMsgEnum.USER_CAN_NOT_DELETE_NOT_CREATOR.getCode()+"");
            removeById(id);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void forceEndPlan(String id) {
        //参与者强制结束
        UserMotionPlanEntity plan = getById(id);
        Assert.isFalse(plan == null, ExceptionMsgEnum.USER_HAS_JOIN_NOT_EXIST.getCode()+"");
        Assert.isFalse(!MotionPlanStatusEnum.IN_PROGRESS.getCode().equals(plan.getStatus()) , ExceptionMsgEnum.USER_CAN_NOT_FORCE_END_NOT_IN_PROGRESS.getCode()+"");
        Assert.isFalse(!plan.getParticipantUserId().equals(UserInfoUtil.getUserId()), ExceptionMsgEnum.USER_CAN_NOT_FORCE_END.getCode()+"");
        //强制结束、更新状态、更新完成状态
        this.baseMapper.completePlan(id,CompleteTypeEnum.COMPLETE_FORCE.getCode());
        //消费金额
        usersDao.completeAndUnlockEnergy(UserInfoUtil.getUserId(),plan.getEmerge(),plan.getMotionMileage()) ;
        //TODO 分销
        completePlan(plan);
    }

    @Override
    public void startPlan(UserStartPlanReq req) {
        UserMotionPlanEntity userMotionPlanEntity = this.baseMapper.selectById(req.getId());
        Assert.isFalse(!userMotionPlanEntity.getUserId().equals(UserInfoUtil.getUserId()),ExceptionMsgEnum.RECORD_NOT_EXIST.getCode()+"");
        Assert.isFalse(StringUtils.isBlank(userMotionPlanEntity.getParticipantUserId()),"参与者不能为空");
        Assert.isFalse(!userMotionPlanEntity.getStatus().equals(MotionPlanStatusEnum.IN_PROGRESS.getCode()),"计划状态错误");
        //距离
        Double distance = usersDao.selectDistance(userMotionPlanEntity.getParticipantUserId(),req.getPoint()) ;

        Assert.isFalse(nearByDistance.compareTo(distance) > 0,"距离过远，在"+nearByDistance+"米范围内才能开始计划");

        //TODO 验证发起人是否在范围内
        //开始计划
        this.baseMapper.startPlan(req);
    }


}